package com.u.social.recommend.service.articles;

import com.u.social.recommend.model.ArticleDTO;
import jakarta.annotation.PostConstruct;
import lombok.Data;
import org.checkerframework.checker.units.qual.A;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @program: u-social
 * @description: 重排策略
 * @author: Alex Wu
 * @createDate: 2025-04-09 14:17
 **/

@Service
public class ReRankingService {

    public List<ArticleDTO> reRank(List<ArticleDTO> articles) {
        // step1 按照活动分配流量重排
        List<ArticleDTO> reRankByActivityTypeList = this.reRankByActivityType(articles);
        // step2 按照相似类型错开重排
        List<ArticleDTO> reRankBySimilarTypeList = this.reRankBySimilarType(reRankByActivityTypeList);
        // step3 按照广告重排
        List<ArticleDTO> result = this.reRankByAD(reRankBySimilarTypeList, adsArticles);
        return result;
    }

    /**
     * 重排广告
     * @param articles 文章列表
     * @return 排序后的文章列表
     */
    private List<ArticleDTO> reRankByAD(List<ArticleDTO> articles, List<ArticleDTO> adsArticles) {
        // 查找articles的文章，是否存在于广告当中，如果有，则将它提到前20的位置

        for (ArticleDTO ad : adsArticles) {
            for (int i = 0; i < articles.size(); i++) {
                if (articles.get(i).getId().equals(ad.getId())) {
                    // 随机生成一个前20的位置
                    int randomIndex = (int) (Math.random() * Math.min(20, articles.size()));
                    // 将广告放到到随机位置
                    articles.remove(i);
                    articles.add(randomIndex, ad);
                    break;
                }
            }
        }
        return articles;
    }

    /**
     * 重排类型，前5个如果相同的类型则将他们打散放在后面
     * @param articles 文章列表
     * @return 排序后的文章列表
     */
    private List<ArticleDTO> reRankBySimilarType(List<ArticleDTO> articles) {
        // 分批获取5个一组，如果类型相同，则打散分一些放在尾部
        // 分批获取5个一组
        List<ArticleDTO> result = new ArrayList<>();
        List<ArticleDTO> buffer = new ArrayList<>();

        for (int i = 0; i < articles.size(); i++) {
            buffer.add(articles.get(i));
            if (buffer.size() == 5 || i == articles.size() - 1) {
                // 检查类型是否相同
                String type = buffer.get(0).getTags();
                boolean allSameType = buffer.stream().allMatch(article -> article.getTags().equals(type));
                if (allSameType) {
                    // 如果类型相同，将部分打散放到尾部
                    result.addAll(buffer.subList(0, 2)); // 保留前两个
                    result.addAll(buffer.subList(2, buffer.size())); // 剩余放到尾部
                } else {
                    result.addAll(buffer);
                }
                buffer.clear();
            }
        }
        return result;
    }


    @Data
    static class ArticleType {
        private Float proportion; // 比例
        private String type; // 类型
    }

    private List<ArticleType> types = new ArrayList<>();
    private List<ArticleDTO> adsArticles = new ArrayList<>();


    @PostConstruct
    public void init() {
        // 初始化类型
        ArticleType articleType1 = new ArticleType();
        articleType1.setProportion(0.8f);
        articleType1.setType("直播");  //最近在扶持直播类型
        types.add(articleType1);

        ArticleType articleType2 = new ArticleType();
        articleType2.setProportion(0.5f);
        articleType2.setType("农业"); //最近在扶持农业类型
        types.add(articleType2);

        ArticleType articleType3 = new ArticleType();
        articleType3.setProportion(0.3f);
        articleType3.setType("美妆"); // 最后在扶持美妆类型
        types.add(articleType3);


        // 初始化广告
        ArticleDTO ad1 = new ArticleDTO();
        ad1.setId(1L);
        ad1.setTitle("广告1");
        ad1.setContent("广告1内容");
        ad1.setScore(0.8f);
        adsArticles.add(ad1);


    }

    /**
     * 重排类型，根据活动类型分配优先流量
     * @param articles 文章列表
     * @return 排序后的文章列表
     */

    public List<ArticleDTO> reRankByActivityType(List<ArticleDTO> articles) {
        // 根据articles的类型, 然后查找types的相同的类型，将分数，乘上比例，无则乘以0.2f,最后进行排序
        List<ArticleDTO> result = new ArrayList<>();
        for (ArticleDTO article : articles) {
            String articleType = article.getTags();
            // 查找相同类型的比例
            float proportion = types.stream()
                    .filter(type -> type.getType().equals(articleType))
                    .map(ArticleType::getProportion)
                    .findFirst()
                    .orElse(0.2f); // 无则乘以0.2f
            // 更新分数
            article.setScore(article.getScore() * proportion);
            result.add(article);
        }
        result.sort((a1, a2) -> Float.compare(a2.getScore(), a1.getScore()));
        return result;
    }


}
